package com.xxx.ratelimiter;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.springframework.stereotype.Component;

/**
 * guava限流器Factory
 */
@Component
public class GuavaRateLimiterFactory {

	// 存放限流器的map：key为api key，value为该api对应的限流器
	private final Map<String, GuavaRateLimiter> limiterMap = new ConcurrentHashMap<String, GuavaRateLimiter>();
	
	// 读写锁
	private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

	/**
	 * 使用工厂模式创建限流器
	 * @param apiKey  限流的apikey
	 * @param timeUnit 时间单位
	 * @param permits 单位时间内请求次数阈值
	 * @return 限流器
	 */
	public GuavaRateLimiter get(String apiKey, TimeUnit timeUnit, int permits) {
		GuavaRateLimiter rateLimiter = null; // 限流器
		
		try {
			lock.readLock().lock(); // 先加读锁
			
			// 如果限流器已在map中，直接获取并返回
			if(limiterMap.containsKey(apiKey)) {
				rateLimiter = limiterMap.get(apiKey);
			}
		} finally {
			lock.readLock().unlock(); // 释放读锁
		}
		
		if(rateLimiter==null) { // 没有获取到限流器，说明是第一次创建
			try {
				lock.writeLock().lock(); // 再加写锁
				
				// 再次判断该限流器是否已在map
				if(limiterMap.containsKey(apiKey)) { 
					rateLimiter = limiterMap.get(apiKey);
				}
				
				if(rateLimiter==null) { // 如果还是没有获取到，则创建一个限流器，并放入map
					rateLimiter = new GuavaRateLimiter(apiKey, permits);
					limiterMap.put(apiKey, rateLimiter); // key为api key，value为GuavaRateLimiter对象
				}
			} finally {
				lock.writeLock().unlock(); // 释放写锁
			}
		}
		
		return rateLimiter;
	}
	
}
